﻿using Nop.Core.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;

namespace Nop.Core.Domain.Logistics
{
    public class LogisticsInformationSettings : ISettings
    {
        /// <summary>
        /// Gets or sets a value indicating whether logistics function is closed
        /// </summary>
        public bool Closed { get; set; }

        /// <summary>
        /// The membership expire days caculated in hours.
        /// </summary>
        public bool MembershipInHour { get; set; }

        /// <summary>
        /// Serialized string for membership options.
        /// </summary>
        public string MembershipOptions { get; set; }

        /// <summary>
        /// The product variant id of the virtual package for non-membership
        /// </summary>
        public int PackageNonMemberProductVarianId { get; set; }

        /// <summary>
        /// The product variant id of the virtual package for membership
        /// </summary>
        public int PackageForMemberProductVarianId { get; set; }

        /// <summary>
        /// The product variant id of rechedule order service for express
        /// </summary>
        public int PackageModificationChargeProductVarianId { get; set; }

        /// <summary>
        /// The product variant id of the special service for express
        /// </summary>
        public int SpecialServiceProductVarianId { get; set; }

        /// <summary>
        /// Allow guest to place order
        /// </summary>
        public bool AllowGuestOrder { get { return false; } set { } }

        /// <summary>
        /// Payment method used for logistics
        /// </summary>
        public string PaymentMethodSystemName { get; set; }

        /// <summary>
        /// The regular size
        /// </summary>
        public decimal RegularDimensionSize { get; set; }

        /// <summary>
        /// The max size limitation
        /// </summary>
        public decimal MaxDimensionSize { get; set; }

        /// <summary>
        /// The size consider to be oversize
        /// </summary>
        public decimal OversizeDimensionSize { get; set; }

        /// <summary>
        /// The max size of the single side
        /// </summary>
        public decimal SingleMaxDimensionSize { get; set; }

        /// <summary>
        /// The regular weight
        /// </summary>
        public decimal RegularWeight { get; set; }

        /// <summary>
        /// The max weight limitation
        /// </summary>
        public decimal MaxWeight { get; set; }

        /// <summary>
        /// The max package number allowed per location
        /// </summary>
        public int MaxPackagePerLocation { get; set; }

        /// <summary>
        /// The max package number allowed per location for Volume shipper
        /// </summary>
        public int VolumeMaxPackagePerLocation { get; set; }

        /// <summary>
        /// The max location allowed
        /// </summary>
        public int MaxLocationNumber { get; set; }

        /// <summary>
        /// The max length of comment
        /// </summary>
        public int MaxCommentLength { get; set; }

        /// <summary>
        /// The max avaliable days to show for choosing a pickup date
        /// </summary>
        public int AvaliableDaysForPickup { get; set; }

        /// <summary>
        /// The max avaliable days to schedule delivery
        /// </summary>
        public int AvaliableDaysToScheduleDelivery { get; set; }

        /// <summary>
        /// The allowed gap in hours for select pickup time
        /// </summary>
        public int AllowedHoursForPickup { get; set; }

        /// <summary>
        /// Block mobile packages status updates within 2 minites
        /// </summary>
        public bool BlockQuickStatusUpdate { get; set; }

        /// <summary>
        /// The Bing map API key
        /// </summary>
        public string BingMapKey { get; set; }

        /// <summary>
        /// Enable shipping access on the top menu
        /// </summary>
        public bool OnTopMenu { get; set; }

        /// <summary>
        /// Include delivered packages for tracking
        /// </summary>
        public bool TrackingIncludeDelivered { get; set; }

        public bool EnableEditOnTracking { get; set; }

        public int? LogisticsServiceStoreId { get; set; }

        #region Rates & Charge

        // TODO: Move to product related DB
        public decimal RegularCharge { get; set; }
        public decimal NonNemberRegularCharge { get; set; }
        public decimal OverSizeCharge { get; set; }
        public decimal OverWeightCharge { get; set; }
        public decimal DangerousGoodCharge { get; set; }
        public decimal VerticalHandleCharge { get; set; }
        public decimal NightDeliverCharge { get; set; }
        public decimal SatDeliverCharge { get; set; }
        public decimal FragileCharge { get; set; }
        public decimal InterDistrictCharge { get; set; }
        public decimal ResidentialCharge { get; set; }
        public decimal ReturnCharge { get; set; }
        public decimal FuelSurchargeRate { get; set; }
        public decimal TaxRate { get; set; }
        public decimal MaxInsuranceValue { get; set; }
        public decimal InsuranceChargeStep { get; set; }
        public decimal InsuranceChargePercentage { get; set; }
        public bool EnableGiftCard { get; set; }
        public decimal AdditionalDeliveryCharge { get; set; }
        public decimal AdditionalScheduleDeliveryCharge { get; set; }
        public decimal StoreOrderLowRateAmount { get; set; }
        public decimal StoreOrderRate { get; set; }
        public decimal StoreOrderLowRate { get; set; }
        public decimal MemberShipWithFixedRateCharge { get; set; }
        public decimal SpecialServiceCharge { get; set; }
        public int TaxCategoryId { get; set; }
        #endregion

        #region Globalpayment

        public string GpGlobalPaymentUrl { get; set; }
        public string GpMerchPass { get; set; }
        public bool GpDebug { get; set; }
        public decimal? GpDebugTotal { get; set; }

        #endregion

        #region Commission

        public decimal CourierCommissionRate { get; set; }

        #endregion

        #region Bulk order

        public int MaxBulkOrderAddress { get; set; }
        public string BulkOrderAdditionalInfo { get; set; }

        #endregion

        /// <summary>
        /// The page size of the grid
        /// </summary>
        public int GridPageSize { get; set; }

        /// <summary>
        /// Order pacakge history in months
        /// </summary>
        public int OrderHistoryInMonths { get; set; }

        #region Tracking

        public string TrackingNumberRegex { get; set; }

        #endregion

        #region Package processing

        public int LeadStopsToLockStatus { get; set; }

        public bool EnableDumpState { get; set; }

        #endregion
    }

    public class MembershipOption
    {
        public int Value { get; set; }
        public int ProductVariantId { get; set; }
        public int Order { get; set; }
    }

    public static class LogisticsInformationSettingsExtension
    {
        public static List<MembershipOption> LoadMembershipOptions(this LogisticsInformationSettings settings)
        {
            var s = settings.MembershipOptions;
            if (String.IsNullOrWhiteSpace(s))
            {
                return null;
            }

            XmlSerializer xs = new XmlSerializer(typeof(MembershipOption[]));

            try
            {
                using (var sr = new StringReader(s))
                {
                    var options = (MembershipOption[])xs.Deserialize(sr);
                    options.OrderBy(o => o.Order);
                    return new List<MembershipOption>(options);
                }
            }
            catch (InvalidOperationException)
            {
                return null;
            }
        }
    }
}
